package com.neusoft.neuiotms.dcam.fixed.service.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Lists;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.bizcore.web.utils.EasyPoiExcelUtil;
import com.neusoft.neuiotms.dcam.constant.DCAMConsts;
import com.neusoft.neuiotms.dcam.fixed.converter.ProductConverter;
import com.neusoft.neuiotms.dcam.fixed.dto.ProductDTO;
import com.neusoft.neuiotms.dcam.fixed.model.AssetType;
import com.neusoft.neuiotms.dcam.fixed.model.Product;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetTypeRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.ProductRepository;
import com.neusoft.neuiotms.dcam.fixed.service.ProductService;
import com.neusoft.neuiotms.dcam.fixed.vo.ProductImportVO;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private ProductConverter productConverter;
    //    @Autowired
    //    private AssetService assetService;
    @Autowired
    private AssetTypeRepository assetTypeRepository;

    @Override
    public ProductDTO create(final ProductDTO dto) {
        final Product model = this.productConverter.toModel(dto);
        this.productRepository.save(model);
        return this.productConverter.toDTO(model);
    }

    @Override
    public void delete(final Long id) {
        try {
            this.productRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        //        final List<Asset> assetList = this.assetService.findByProduct(model);
        //        if ((assetList != null) && !assetList.isEmpty()) {
        //            throw new UnitedException("该产品已生成资产，请先删除资产", new Object[] {id });
        //        }

        this.productRepository.deleteById(id);
    }

    @Override
    public ProductDTO update(final Long id, final ProductDTO dto) {
        Product model;
        try {
            model = this.productRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        dto.setId(model.getId());
        model = this.productConverter.toModel(dto);
        this.productRepository.save(model);

        return this.productConverter.toDTO(model);
    }

    @Override
    public List<ProductDTO> index(final Searchable searchable) {
        final List<Product> models = this.productRepository.index(searchable);
        return this.productConverter.toListDTO(models);
    }

    @Override
    public ProductDTO details(final Long id) {
        final Product model;
        try {
            model = this.productRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        return this.productConverter.toDTO(model);
    }

    @Override
    public Page<ProductDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<Product> result = this.productRepository.search(pageable, searchable);
        return this.productConverter.toPageDTO(result);
    }

    @Override
    public List<ProductDTO> findByAssetType(final AssetType assettype) {
        final List<Product> models = this.productRepository.findByAssetType(assettype);
        return this.productConverter.toListDTO(models);
    }

    @Override
    public Workbook template(String belongs) {
        final List<ProductImportVO> list = new ArrayList<>();
        final Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("物料导入模板", "物料导入模板", ExcelType.XSSF),
                ProductImportVO.class, list);

        //资产类型候选
        final List<AssetType> allTypes = this.assetTypeRepository.findAll();
        final AssetType belongsAssetType = allTypes.stream().filter(it -> it.getCode().equals(belongs)).findAny().get();
        final List<AssetType> secondLevelTypes = allTypes.stream()
                .filter(it -> (null != it.getParent()) && it.getParent().getCode().equals(belongsAssetType.getCode()))
                .collect(Collectors.toList());

        final List<AssetType> thirdLevelTypes = Lists.newArrayList();
        for (final AssetType type : secondLevelTypes) {
            thirdLevelTypes.addAll(allTypes.stream()
                    .filter(it -> (null != it.getParent()) && it.getParent().getCode().equals(type.getCode()))
                    .collect(Collectors.toList()));
        }

        final List<AssetType> forthLevelTypes = Lists.newArrayList();
        for (final AssetType type : thirdLevelTypes) {
            forthLevelTypes.addAll(allTypes.stream()
                    .filter(it -> (null != it.getParent()) && it.getParent().getCode().equals(type.getCode()))
                    .collect(Collectors.toList()));
        }

        final List<String> typeConstraint = new ArrayList<>();
        forthLevelTypes.stream().forEach(l -> {
            typeConstraint.add(l.getName() + DCAMConsts.DICTIONARY_SPLITOR + l.getCode());
        });

        final Iterator<Sheet> iterator = workbook.iterator();
        while (iterator.hasNext()) {
            final Sheet sheet = iterator.next();
            EasyPoiExcelUtil.sheetConstraintXSSF(sheet, DCAMConsts.ASSET_START_CONSTRAINT_ROW,
                    DCAMConsts.ASSET_CONSTRAINT_ROW, 1,
                    1, typeConstraint);

        }
        return workbook;
    }

    @Override
    public String upload(final MultipartFile file) {
        final StringBuilder errorMsg = new StringBuilder();
        final ImportParams params = new ImportParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        params.setNeedVerify(true);
        try {
            final ExcelImportResult<ProductImportVO> result =
                    ExcelImportUtil.importExcelMore(file.getInputStream(), ProductImportVO.class, params);
            if (result.isVerifyFail()) {
                final List<ProductImportVO> failList = result.getFailList();
                failList.forEach(l -> {
                    errorMsg.append("第" + (l.getRowNum() + 1) + "行," + l.getErrorMsg() + "! \n");
                });

            }
            final List<Product> models = new ArrayList<>();
            final List<ProductImportVO> saveList = result.getList();
            for (final ProductImportVO p : saveList) {
                final Product model = this.productConverter.toModel(p);
                //类型
                if (!StringUtils.isEmpty(p.getAssetTypeName())
                        && p.getAssetTypeName().contains(DCAMConsts.DICTIONARY_SPLITOR)) {
                    final String[] types = p.getAssetTypeName().split(DCAMConsts.DICTIONARY_SPLITOR);
                    try {
                        final AssetType type = this.assetTypeRepository.findByCode(types[1]);
                        model.setAssetType(type);
                    } catch (final EntityNotFoundException e) {
                        throw new UnitedException("资产类型不存在", new Object[] {types[1] });
                    }
                }
                models.add(model);
            }
            if (!models.isEmpty()) {
                this.productRepository.saveAll(models);
            }

        } catch (final Exception e) {
            e.printStackTrace();
            ProductServiceImpl.log.error("上传失败", e);
            throw new UnitedException(e.getMessage(), new Object[] {});
        }

        return errorMsg.toString();
    }

}
